trigger Lead_UpdateAccount on Lead (before insert, before update, after delete, after insert, after undelete, 
after update) {
    if(Trigger.isBefore){
        System.Debug('================> Starting Lead Before Trigger');
        // Create a List of Leads to Update
        List<Lead> LeadsToUpdate = new List<Lead>();
        List<Lead> LeadsToSync = new List<Lead>();
        
        // Create a list for Leads with no Account
        List<Lead> LeadsWithNoAccount = new List<Lead>();
        
        Set<Id> AccountIds = new Set<Id>();
        for(Integer i=0;i<Trigger.New.size();i++){
            if(Trigger.isInsert){
                if(Trigger.New[i].Account__c<> null &&
                    Trigger.New[i].Override_Account_Fields__c == false){
                        LeadsToUpdate.add(Trigger.New[i]);
                        AccountIds.add(Trigger.New[i].Account__c);
                    }
                // Create a list of Leads to find an Account for
                
                if(Trigger.New[i].Account__c==null){
                    LeadsWithNoAccount.add(Trigger.New[i]);
                }
            }else if(Trigger.isUpdate){
                System.Debug('================> Entering before update code');
                if(Trigger.New[i].Account__c <> null && 
                    Trigger.New[i].Account__c<>Trigger.Old[i].Account__c && 
                    Trigger.New[i].Override_Account_Fields__c == false){
                    LeadsToUpdate.add(Trigger.New[i]);
                    AccountIds.add(Trigger.New[i].Account__c);
                    AccountIds.add(Trigger.Old[i].Account__c);
                }
            }
            
        }
        
        
        
        if(LeadsWithNoAccount.size()>0){
                // Create a set of Company Names and Websites to Search
                Set<String> Companies = new Set<String>();
                Set<String> Websites = new set<String>();
                Set<String> CompaniesToAvoid = new set<String>{'[Not Provided]','self','Self employed'};
                For(Lead l : LeadsWithNoAccount){
                    if(!CompaniesToAvoid.contains(l.Company)){
                        Companies.add(l.Company);
                    }
                    if(l.Website != null){
                        Websites.add(l.Website);
                    }
                }
                List<Lead> LeadsWithAccount = new List<Lead>();
                if(Companies.size()>0 || Websites.size()>0){
                    for(Account a : [select Id, Name, Website from Account where Name in :Companies or Website in :Websites]){
                        for(Lead l : LeadsWithNoAccount){
                            if(l.Company == a.Name || l.Website == a.Website){
                                l.Account__c = a.Id;
                                System.Debug('===============> Override Account Fields: '+l.Override_Account_Fields__c);
                                if(l.Override_Account_Fields__c == false){
                                    LeadsToUpdate.add(l);
                                    AccountIds.add(a.Id);
                                }
                                
                            }
                        }
                    }
                }
            }
        
        if(LeadsToUpdate.size()>0){
            System.Debug('================> Found '+LeadsToUpdate.size()+' Leads to update Account info on');
            // Create a map of the Account data
            Map<Id,Account> Accounts = new Map<Id,Account>();
                // FIELD LIST
            for(Account a : [select Name, Status__c, Status_Explanation__c, CRM_System__c, Salesforce_Verified__c from Account where Id in : AccountIds]){
                Accounts.put(a.Id,a);
            }
            
            // Map the Account values to the Leads
            Boolean updateAccounts = false;
            for(Lead l : LeadsToUpdate){
                // FIELD LIST
                if(Accounts.get(l.Account__c).Status__c != null){
                    l.Status = Accounts.get(l.Account__c).Status__c;
                }else{
                    Accounts.get(l.Account__c).Status__c = l.Status;
                    updateAccounts = true;
                }
                l.Status_Explanation__c = Accounts.get(l.Account__c).Status_Explanation__c;
                l.Company = Accounts.get(l.Account__c).Name;
                l.CRM_System__c = Accounts.get(l.Account__c).CRM_System__c;
                l.Salesforce_Verified__c = Accounts.get(l.Account__c).Salesforce_Verified__c;
            }
            if(updateAccounts){
                update Accounts.values();
            }
        }else{
            System.Debug('================> Found no Leads to Update');
        }
        
        
        
        System.Debug('================> End of Lead Before Trigger');
        AccountIds.clear();
    } // End of isBefore
    
    Set<Id> AccountIds = new Set<Id>();
    
    if(Trigger.isAfter && (!Trigger.isDelete)){
        
        System.Debug('================> Starting Lead After Trigger');
            Lead NewLead = new Lead();
            Lead OldLead = new Lead();
            
            // Create a set of the Leads IDs that were updated
            Set<Id> UpdatedLeads = new Set<Id>();
            
            
            
            for(Integer i=0;i<Trigger.New.size();i++){
                NewLead = Trigger.New[i];
                if(Trigger.isUpdate){
                    OldLead = Trigger.Old[i];
                    if(NewLead.Account__c<>null && (NewLead.Account__c==OldLead.Account__c || NewLead.Override_Account_Fields__c == true)){
                        if(NewLead.Status<>OldLead.Status || 
                            NewLead.Status_Explanation__c <> OldLead.Status_Explanation__c ||
                            NewLead.Company <> OldLead.Company || 
                            NewLead.CRM_System__c <> OldLead.CRM_System__c ||
                            NewLead.Salesforce_Verified__c <> OldLead.Salesforce_Verified__c ||
                            NewLead.Valid_Lead__c <> OldLead.Valid_Lead__c){
                            UpdatedLeads.add(NewLead.Id);
                        }
                        
                    }
                    if(NewLead.Account__c <> OldLead.Account__c){
                    	if(newLead.Account__c <> null) AccountIds.add(newLead.Account__c);
                    	if(oldlead.account__c <>null) AccountIds.add(OldLead.Account__c);
                    }
                    if(NewLead.Valid_Lead__c <> OldLead.Valid_Lead__c){
                    	AccountIds.add(NewLead.Account__c);
                    }
                }
                if((Trigger.isInsert || Trigger.isUndelete) && NewLead.Account__c<>null){
                    if(NewLead.Override_Account_Fields__c == true) UpdatedLeads.add(NewLead.Id);
                    AccountIds.add(NewLead.Account__c);
                }
                
            }
            if(UpdatedLeads.size()>0 && LeadSync_AsyncApex.firstTrigger == true){
                LeadSync_AsyncApex.firstTrigger = false;
                System.Debug('================> Found '+UpdatedLeads.size()+' Leads to Update');
                LeadSync_AsyncApex.SyncLeadInfo(UpdatedLeads);
            }else{
                System.Debug('================> Found no Leads to Update');
            }
	            
	        
            
            
            
            System.Debug('================> End of Lead After Trigger');
    }// End of isAfter
    
    if(Trigger.isDelete){
    	for(Lead l : Trigger.old){
			if(l.Account__c <> null) AccountIDs.add(l.Account__c);
		}
    }
    if(AccountIds.contains(null)) AccountIds.remove(null);
    if(AccountIds.size()>0){
    	list<Account> AccountsToUpdate = new List<Account>();
    	System.Debug('Updating '+AccountIds.size() + ' Accounts');
    	System.Debug('Account IDs ==> '+AccountIds);
	
	    for(AggregateResult r : [select Account__c acct, count(Id) from Lead 
	    	where Account__c in :AccountIDs and Valid_Lead__c = 'True' and IsConverted = False group by Account__c]){
        		AccountsToUpdate.add(new Account(Id=(string) r.get('acct'), Leads__c = (integer) r.get('expr0')));
        		Boolean RemoveAccount = AccountIDs.remove((string) r.get('acct'));
        }
        if(AccountIDs.size()>0){ // Then there are some Accounts with no Leads
        	System.Debug('===========================> There are some Accounts with no Leads');
        	for(Id AccountID : AccountIDs){
        		AccountsToUpdate.add(new Account(Id=AccountID, Leads__c = 0));
        	}
        }
        System.Debug('Accounts to Update: '+AccountsToUpdate.size());
        if(AccountsToUpdate.size()>0) update AccountsToUpdate;
    }

}